package com.opencee.cloud.base.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.opencee.boot.db.mybatis.service.impl.SupperServiceImpl;
import com.opencee.cloud.base.constants.BaseAccountType;
import com.opencee.cloud.base.entity.BaseAccountCredentialEntity;
import com.opencee.cloud.base.mapper.BaseAccountCredentialMapper;
import com.opencee.cloud.base.service.IBaseAccountCredentialService;
import com.opencee.cloud.base.vo.BaseAccountStatusVO;
import com.opencee.common.exception.BaseFailException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 账号 服务实现类
 * </p>
 *
 * @author liuyadu
 * @since 2021-04-16
 */
@Service
public class BaseAccountCredentialServiceImpl extends SupperServiceImpl<BaseAccountCredentialMapper, BaseAccountCredentialEntity> implements IBaseAccountCredentialService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 查询账号信息
     *
     * @param account
     * @param baseAccountType
     * @return
     */
    @Override
    public BaseAccountCredentialEntity getBy(String account, BaseAccountType baseAccountType) {
        QueryWrapper<BaseAccountCredentialEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccountCredentialEntity::getAccount, account)
                .eq(BaseAccountCredentialEntity::getAccountType, baseAccountType.name());
        return getOne(queryWrapper);
    }

    /**
     * 根据登录名查询账号信息
     *
     * @param username
     * @return
     */
    @Override
    public BaseAccountCredentialEntity getByUsername(String username) {
        return getBy(username, BaseAccountType.USERNAME);
    }

    /**
     * 根据手机号查询账号信息
     *
     * @param mobile
     * @return
     */
    @Override
    public BaseAccountCredentialEntity getByMobile(String mobile) {
        return getBy(mobile, BaseAccountType.MOBILE);
    }

    /**
     * 根据邮箱查询账号信息
     *
     * @param email
     * @return
     */
    @Override
    public BaseAccountCredentialEntity getByEmail(String email) {
        return getBy(email, BaseAccountType.EMAIL);
    }


    /**
     * 添加登录账号
     *
     * @param account
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(BaseAccountCredentialEntity account) {
        if (account.getUserId() == null) {
            throw new BaseFailException("用户Id不能为空");
        }
        BaseAccountType type = BaseAccountType.valueOf(account.getAccountType());
        if (exists(account.getAccount(), type)) {
            // 账号已被注册
            throw new BaseFailException(String.format("%s:%s已被注册", type.getText(), account.getAccount()));
        }
        if (StringUtils.isBlank(account.getCredentials())) {
            // 随机密码
            account.setCredentials(RandomUtil.randomString(16));
        }
        if (account.getVerified() == null) {
            account.setVerified(false);
        }
        if (account.getStatus() == null) {
            account.setStatus(1);
        }
        BaseAccountCredentialEntity target = new BaseAccountCredentialEntity();
        BeanUtils.copyProperties(account, target);
        target.setDeleted(0);
        target.setCredentials(passwordEncoder.encode(account.getCredentials()));
        return baseMapper.insert(target) > 0;
    }

    /**
     * 修改账号信息
     *
     * @param account
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean update(BaseAccountCredentialEntity account, String oldAccount) {
        BaseAccountType type = BaseAccountType.valueOf(account.getAccountType());
        BaseAccountCredentialEntity saved = getBy(oldAccount, type);
        if (saved == null) {
            throw new BaseFailException("账号不存在!");
        }
        if (!saved.getAccount().equals(account.getAccount())) {
            // 和原来不一致重新检查唯一性
            if (exists(account.getAccount(), type)) {
                throw new BaseFailException(String.format("%s:%s已被注册", type.getText(), account.getAccount()));
            }
        }
        account.setId(saved.getId());
        return updateById(account);
    }

    /**
     * 检测账号是否存在
     *
     * @param account
     * @param baseAccountType
     * @return
     */
    @Override
    public boolean exists(String account, BaseAccountType baseAccountType) {
        QueryWrapper<BaseAccountCredentialEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccountCredentialEntity::getAccount, account)
                .eq(BaseAccountCredentialEntity::getAccountType, baseAccountType);
        return count(queryWrapper) > 0;
    }

    /**
     * 验证密码是否一致
     *
     * @param userId
     * @param password
     * @return
     */
    @Override
    public boolean validPassword(Long userId, String password) {
        boolean success = false;
        QueryWrapper<BaseAccountCredentialEntity> wrapper = new QueryWrapper();
        wrapper.lambda()
                .eq(BaseAccountCredentialEntity::getAccountType, BaseAccountType.USERNAME.name())
                .eq(BaseAccountCredentialEntity::getUserId, userId);
        BaseAccountCredentialEntity account = getOne(wrapper);
        if (account != null) {
            success = passwordEncoder.matches(password, account.getCredentials());
        }
        return success;
    }

    /**
     * 根据用户ID重置用户密码
     *
     * @param userId
     * @param password
     * @return
     */
    @Override
    public boolean updatePasswordByUserId(Long userId, String password) {
        BaseAccountCredentialEntity account = new BaseAccountCredentialEntity();
        account.setCredentials(passwordEncoder.encode(password));
        QueryWrapper<BaseAccountCredentialEntity> wrapper = new QueryWrapper();
        wrapper.lambda()
                .in(BaseAccountCredentialEntity::getAccountType, BaseAccountType.USERNAME.name(), BaseAccountType.EMAIL.name(), BaseAccountType.MOBILE.name())
                .eq(BaseAccountCredentialEntity::getUserId, userId);
        return update(account, wrapper);
    }

    /**
     * 根据认证类型重置用户密码
     *
     * @param userId
     * @param baseAccountType
     * @return
     */
    @Override
    public boolean updatePasswordByAccountType(Long userId, BaseAccountType baseAccountType, String password) {
        BaseAccountCredentialEntity account = new BaseAccountCredentialEntity();
        account.setCredentials(passwordEncoder.encode(password));
        QueryWrapper<BaseAccountCredentialEntity> wrapper = new QueryWrapper();
        wrapper.lambda()
                .eq(BaseAccountCredentialEntity::getUserId, userId)
                .eq(BaseAccountCredentialEntity::getAccountType, baseAccountType.name());
        return update(account, wrapper);
    }

    /**
     * 根据用户ID删除账号
     *
     * @param userId
     * @return
     */
    @Override
    public boolean removeByUserId(Long userId) {
        QueryWrapper<BaseAccountCredentialEntity> wrapper = new QueryWrapper();
        wrapper.lambda()
                .eq(BaseAccountCredentialEntity::getUserId, userId);
        return remove(wrapper);
    }

    /**
     * 根据账号类型删除用户
     *
     * @param userId
     * @param baseAccountType
     * @return
     */
    @Override
    public boolean removeByAccountType(Long userId, BaseAccountType baseAccountType) {
        QueryWrapper<BaseAccountCredentialEntity> wrapper = new QueryWrapper();
        wrapper.lambda()
                .eq(BaseAccountCredentialEntity::getUserId, userId)
                .eq(BaseAccountCredentialEntity::getAccountType, baseAccountType.name());
        return remove(wrapper);
    }

    /**
     * 更新登录成功日志
     *
     * @param userId
     * @param baseAccountType
     * @param ip
     * @param date
     * @return
     */
    @Override
    public boolean saveLoginLog(Long userId, BaseAccountType baseAccountType, String ip, Date date) {
        return false;
    }

    /**
     * 查询用户登录账号状态
     *
     * @param userId
     * @return
     */
    @Override
    public List<BaseAccountStatusVO> listAccountStatus(Long userId) {
        return baseMapper.selectAccountStatus(userId);
    }


}
